﻿using AutoMapper;
using Blm.Utils.Extensions;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Enums;
using VisionCloud.Core.Model.Enums.Schedule;
using VisionCloud.Core.Model.Schedule;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.Configs;
using VisionCloud.Domain.DtoModel.Inner;
using VisionCloud.Domain.DtoModel.Schedule.WorkOrder;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.Repository.Interface.Schedule;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Service.Fms;
using VisionCloud.Service.Sys;
using VisionCloud.Utility;

namespace VisionCloud.Service.Schedule
{
    public class WorkOrderService
    {
        public IWorkOrderRepository WorkOrderRepository { get; set; }

        public ISysDeviceRepository SysDeviceRepository { set; get; }

        public IMsProjectRepository MsProjectRepository { set; get; }

        public IMsUserToProjectRepository MsUserToProjectRepository { set; get; }

        public IRsRobotMeasureDataRepository RsRobotMeasureDataRepository { set; get; }

        public ISysUserRepository SysUserRepository { set; get; }

        public SmsService SmsService { set; get; }

        public ILogger<WorkOrderService> Logger { set; get; }

        public IMapper Mapper { set; get; }

        public IUnitOfWork UnitOfWork { get; set; }

        public ProjectExternalService ProjectExternalService { get; set; }

        public ProjectDCService ProjectDCService { set; get; }

        public SmsService smsService { get; set; }

        /// <summary>
        /// 添加工单
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ApiResult> Add(RsWorkOrderAddDto model)
        {
            var order = await WorkOrderRepository.FirstOrDefaultAsync(p => p.BpsTaskId == model.BpsTaskId && !p.IsDeleted);
            if (order != null)
                return new ApiResult { Code = AjaxCode.Fail, Message = $"该Bps工单{model.BpsTaskId}已存在" };

            order = Mapper.Map<RsWorkOrderAddDto, RsWorkOrder>(model);
            order.Id = Guid.NewGuid();
            order.LastUpdatedDate = DateTime.Now;
            order.CreatedDate = DateTime.Now;
            order.IsDeleted = false;
            order.SourceType = 1;
            bool isError = false;
            try
            {
                WorkOrderRepository.Add(order, false);
                var affrows = await UnitOfWork.SaveChangesAsync();
                if (affrows == 0)
                    return new ApiResult { Code = AjaxCode.Error, Message = "新增Bps工单失败" };

                var result = await ProjectExternalService.AddOrUpdateProjectInfo(model.ProjectId);
                if (result == null || result.Code != AjaxCode.Success)
                {
                    isError = true;
                    return new ApiResult { Code = AjaxCode.Error, Message = $"新增Bps工单失败：处理FMS项目{model.ProjectId}数据出错；{result.Message}" };
                }
            }
            catch (Exception ex)
            {
                Logger.LogError($"{ex.Message}，{ex.StackTrace}", ex);
                isError = true;
            }
            finally
            {
                if (isError)
                {
                    //如果处理项目数据失败，则删除工单记录
                    WorkOrderRepository.RemoveById(order.Id);
                    await UnitOfWork.SaveChangesAsync();
                }
            }
            // 收到工单自动发送短信
            //SendSms(model, ipAddress);
            return new ApiResult { Code = AjaxCode.Success, Message = "成功" };
        }

        /// <summary>
        /// 删除工单
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ApiResult> Delete(RsWorkOrderDeleteDto model)
        {
            var order = await WorkOrderRepository.FirstOrDefaultAsync(p => p.BpsTaskId == model.BpsTaskId && !p.IsDeleted);
            if (order == null)
                return new ApiResult { Code = AjaxCode.Fail, Message = $"该Bps工单{model.BpsTaskId}不存在或已删除" };
            if (!order.IsTestTask)
                return new ApiResult { Code = AjaxCode.Fail, Message = $"该Bps工单{model.BpsTaskId}非测试工单，不可删除" };

            WorkOrderRepository.RemoveById(order.Id);
            var affrows = await UnitOfWork.SaveChangesAsync();
            return new ApiResult { Code = AjaxCode.Success, Message = "成功" };
        }

        public List<GetSimpleGroupRspDto> GetSimpleAllList(GetSimpleListDto model)
        {
            var query = WorkOrderRepository.GetAll().Where(x => x.IsDeleted == false);
            if (model.Status == null || !model.Status.Contains(-1))
                query = query.Where(x => model.Status.Contains((int)x.Status));
            var result = query.Where(x => x.CreatedDate >= model.CreateTime)
                .Where(x => string.IsNullOrEmpty(model.KeyWords) || x.ProjectName.Contains(model.KeyWords) || x.ProcedureCode.Contains(model.KeyWords))
                .Select(x => new WorkOrderSimpleDto
                {
                    CreateTime = x.CreatedDate.ToLocalTime().ToString(),
                    Id = x.Id,
                    ProcedureCode = x.ProcedureCode,
                    Status = x.Status,
                    Province = x.Province,
                    ProjectName = x.ProjectName,
                    Longitude = x.Longitude,
                    Latitude = x.Latitude
                }).ToList();
            List<GetSimpleGroupRspDto> list = new List<GetSimpleGroupRspDto>();
            result.Select(x => x.Province).Distinct().ToList().ForEach(x =>
            {
                var tempList = result.Where(o => o.Province == x).OrderByDescending(x => x.CreateTime).ToList();
                list.Add(new GetSimpleGroupRspDto
                {
                    Province = x,
                    WorkOrders = tempList
                });
            });
            list = list.OrderByDescending(x => x.WorkOrders.Count()).ToList();
            return list;
        }

        public WorkOrderDetailDto GetWorkOrderDetail(Guid id)
        {
            var entity = WorkOrderRepository.Where(x => x.Id == id).FirstOrDefault();
            if (entity == null) return null;
            var data = Mapper.Map<WorkOrderDetailDto>(entity);
            return data;
        }

        public async Task<bool> MatchRobot(MatchRobotRqDto request, string ip)
        {
            var robot = SysDeviceRepository.GetAll().Where(x => x.DeviceGuid == request.RobotId)
                .Where(x => x.IsDeleted == false)
                .Where(x => x.IsActive == true)
                .Where(x => x.AvailableStatus == (int)DeviceAvailableStatusEnum.闲置)
                .FirstOrDefault();
            if (robot == null)
            {
                Logger.LogInformation($"测量机器人不可用，deviceId:{request.RobotId}");
                throw new OperationException("测量机器人不可用");
            }
            var order = WorkOrderRepository.GetById(request.WorkOrderId);
            if (order == null)
            {
                Logger.LogInformation($"工单不存在，workOrderId:{request.WorkOrderId}");
                throw new OperationException("工单不存在");
            }

            order.DeviceId = robot.DeviceGuid;
            order.LastUpdatedDate = DateTime.Now;
            order.Status = WorkOrderStatusEnum.未开始;

            robot.AvailableStatus = (int)DeviceAvailableStatusEnum.忙碌;
            robot.LastUpdatedDate = DateTime.Now;

            var user = SysUserRepository.GetById(robot.ActiveUserGuid);

            string msg = "YB0459".SLocalize(user?.Name, order.ProjectName, order.Id);

            WorkOrderRepository.Update(order);
            SysDeviceRepository.Update(robot);
            int result = await UnitOfWork.SaveChangesAsync();
            //await SendMsgForProject(order.ProjectId, ip, msg);
            return result > 0;
        }

        public async Task<bool> CancelMatchRobot(MatchRobotRqDto request, string ip)
        {
            var order = WorkOrderRepository.GetById(request.WorkOrderId);
            if (order == null)
            {
                Logger.LogInformation($"工单不存在，workOrderId:{request.WorkOrderId}");
                throw new OperationException("工单不存在");
            }
            var robot = SysDeviceRepository.GetAll().Where(x => x.DeviceGuid == order.DeviceId).FirstOrDefault();
            if (robot == null)
            {
                Logger.LogInformation($"测量机器人不存在，deviceId:{request.RobotId}");
                throw new OperationException("测量机器人不存在");
            }

            order.DeviceId = null;
            order.LastUpdatedDate = DateTime.Now;
            order.Status = (int)WorkOrderStatusEnum.未分配;

            robot.AvailableStatus = (int)DeviceAvailableStatusEnum.闲置;
            robot.LastUpdatedDate = DateTime.Now;

            var user = SysUserRepository.GetById(robot.ActiveUserGuid);

            string msg = "YB0460".SLocalize(user?.Name, order.ProjectName, order.Id);

            WorkOrderRepository.Update(order);
            SysDeviceRepository.Update(robot);
            int result = await UnitOfWork.SaveChangesAsync();
            //await SendMsgForProject(order.ProjectId, ip, msg);
            return result > 0;
        }

        public List<WorkOrderLocationDto> GetLocaltionList()
        {
            var result = WorkOrderRepository.GetAll().Select(x => new WorkOrderLocationDto
            {
                Id = x.Id,
                Longitude = x.Longitude,
                Latitude = x.Latitude,
                Status = x.Status
            }).ToList();
            return result;
        }

        /// <summary>
        /// 获取全部列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetAllList(GetAllListDto dto)
        {
            var list = (await WorkOrderRepository.WhereAsync(p => !p.IsDeleted && p.Status == dto.Status)).Select(p => new GetAllListResponseModel
            {
                Status = p.Status,
                BpsTaskId = p.BpsTaskId,
                BpsTaskRemark = p.BpsTaskRemark,
                BpsTaskType = p.BpsTaskType,
                BuildingCode = p.BuildingCode,
                BuildingName = p.BuildingName,
                FloorCode = p.FloorCode,
                FloorName = p.FloorName,
                ProcedureCode = p.ProcedureCode,
                ProjectId = p.ProjectId,
                ProjectName = p.ProjectName,
                RobotTaskType = Convert.ToInt32(WorkOrderCodeAndNameMap.GetTaskType(p.ProcedureCode))
            }).Where(p => p.RobotTaskType != 100).ToList();
            return new ApiResult { Code = AjaxCode.Success, Result = list };
        }

        /// <summary>
        /// 上传工单测量结果
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> Upload(UploadRequestDto dto)
        {
            var order = await WorkOrderRepository.FirstOrDefaultAsync(p => p.BpsTaskId == dto.BpsTaskId && !p.IsDeleted);
            if (order == null)
                return new ApiResult { Code = AjaxCode.Fail, Message = $"{dto.BpsTaskId}工单不存在" };
            if (order.Status == WorkOrderStatusEnum.已完成)
                return new ApiResult { Code = AjaxCode.Fail, Message = $"{dto.BpsTaskId}工单已完成，拒绝重复上传结果" };

            var oldStatus = order.Status;
            RsRobotMeasureData model = null;
            try
            {
                //更新数据库
                order.Status = dto.Status > 0 ? (WorkOrderStatusEnum)dto.Status : WorkOrderStatusEnum.已完成;
                WorkOrderRepository.Update(order);
                model = new RsRobotMeasureData
                {
                    Id = Guid.NewGuid(),
                    BpsTaskId = dto.BpsTaskId,
                    IsDeleted = false,
                    Path = dto.JsonFile,
                    Version = dto.Version,
                    RobotCategory = Convert.ToInt32(WorkOrderCodeAndNameMap.GetTaskType(order.ProcedureCode)),
                    CreatedDate = DateTime.Now,
                    LastUpdatedDate = DateTime.Now,
                    CreatedBy = OperatorProvider.Get().Id,
                    LastUpdatedBy = OperatorProvider.Get().Id,
                    StartTime = dto.StartTime,
                    EndTime = dto.EndTime,
                };
                RsRobotMeasureDataRepository.Add(model);

                int affrows = await UnitOfWork.SaveChangesAsync();
                if (affrows > 0)
                {
                    using HttpClientHandler handler = new HttpClientHandler();
                    handler.ServerCertificateCustomValidationCallback = (message, cert, choin, error) => true;
                    using HttpClient client = new HttpClient(handler);
                    var response = await client.GetAsync(dto.JsonFile);
                    if (response != null && response.IsSuccessStatusCode)
                    {
                        var data = await response.Content.ReadAsStringAsync();
                        var request = new WorkOrderFreebackDto()
                        {
                            TaskId = dto.BpsTaskId,
                            StartTime = (dto.StartTime ?? order.StartTime).ToDateTimeStandardString(),
                            EndTime = (dto.EndTime ?? order.EndTime).ToDateTimeStandardString(),
                            Remark = dto.Remark,
                            RobotCode = dto.RobotCode,
                            Data = JToken.Parse(data),
                            Status = dto.Status
                        };
                        Logger.LogInformation("请求工单上传的body数据文件：" + dto.JsonFile);
                        var result = await ProjectDCService.FreeBackWordOrder(request);
                        if (result == null || result.Code != 0)
                            return ApiResult.Error($"FMS工单接口反馈失败：{result?.Message}");
                    }
                    else
                    {
                        return ApiResult.Error($"获取json内容失败：{dto.JsonFile}");
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogError($"{ex.Message}，{ex.StackTrace}", ex);

                //如果出错了，则回滚数据
                order.Status = oldStatus;
                WorkOrderRepository.Update(order);
                if (model != null)
                    RsRobotMeasureDataRepository.Remove(model);

                await UnitOfWork.SaveChangesAsync();

                return ApiResult.Error($"上传工单数据出错：{ex.Message}");
            }

            return ApiResult.Success("Success");
        }

        public RsWorkOrder GetWorkOrder(string bpsTaskId)
        {
            return WorkOrderRepository.GetAll().Where(x => x.BpsTaskId == bpsTaskId).FirstOrDefault();
        }
    }
}